#include "Model.h"

using namespace DirectX;

Model::Model()
{
	ZeroMemory(&m_renderData, sizeof(m_renderData));
	ZeroMemory(&m_rawData, sizeof(m_rawData));
}

Model::Model(ModelRawData rawData, Texture& diffuseColor, Texture& normalMap) : m_rawData(rawData)
{
	SimpleVertex* vertices = new SimpleVertex[m_rawData.numVertices];
	memcpy(vertices, m_rawData.vertices, sizeof(SimpleVertex) * m_rawData.numVertices);
	m_rawData.vertices = vertices;
	ZeroMemory(&m_renderData, sizeof(m_renderData));
	m_renderData.diffuseColor = &diffuseColor;
	m_renderData.normalMap = &normalMap;
}

Model::~Model(void)
{
	ClearD3d();
	delete[] m_rawData.vertices;
}

const ModelRenderData* Model::GetRenderData( void ) const
{
	return &m_renderData;
}

HRESULT Model::InitializeD3D( ID3D11Device* d3dDevice )
{
	HRESULT result;

	ClearD3d();
	m_renderData.vertexStride = sizeof(*m_rawData.vertices);
	m_renderData.vertexOffset = 0;
	m_renderData.numIndizesToDraw = m_rawData.numIndices;
	m_renderData.Color = m_rawData.Color;

	XMMATRIX translation, rotation;
	translation = XMMatrixTranslation(m_rawData.Position.x, m_rawData.Position.y, m_rawData.Position.z);
	rotation = XMMatrixRotationX(m_rawData.Rotation.x);
	rotation *= XMMatrixRotationY(m_rawData.Rotation.y);
	rotation *= XMMatrixRotationZ(m_rawData.Rotation.z);
	m_renderData.Transform = rotation * translation;

	//Create vertex buffer
	D3D11_BUFFER_DESC bufferDesc;
	ZeroMemory( &bufferDesc, sizeof(bufferDesc) );
	bufferDesc.Usage = D3D11_USAGE_DEFAULT;
	bufferDesc.ByteWidth = sizeof( SimpleVertex ) * m_rawData.numVertices;
	bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bufferDesc.CPUAccessFlags = 0;
	D3D11_SUBRESOURCE_DATA bufferInitializationData;
	ZeroMemory( &bufferInitializationData, sizeof(bufferInitializationData) );
	bufferInitializationData.pSysMem = m_rawData.vertices;
	result = d3dDevice->CreateBuffer( &bufferDesc, &bufferInitializationData, &m_renderData.VertexBuffer );
	if( FAILED( result ) )
	{
		return result;
	}
	//Create index buffer
	bufferDesc.Usage = D3D11_USAGE_DEFAULT;
	bufferDesc.ByteWidth = sizeof( WORD ) * m_rawData.numIndices;
	bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	bufferDesc.CPUAccessFlags = 0;
	bufferInitializationData.pSysMem = m_rawData.indices;
	result = d3dDevice->CreateBuffer( &bufferDesc, &bufferInitializationData, &m_renderData.IndexBuffer);
	if( FAILED( result ) )
	{
		return result;
	}
	//setup triangle accessors
	for(int i = 0; i < m_rawData.numIndices - 2; i += 3)
	{
		m_triangleAccessors.push_back(TriangleAccessor(this,
			m_rawData.vertices + m_rawData.indices[i],
			m_rawData.vertices + m_rawData.indices[i + 1],
			m_rawData.vertices + m_rawData.indices[i + 2]));
	}
	return S_OK;
}

void Model::ClearD3d( void )
{
	if( m_renderData.VertexBuffer ) m_renderData.VertexBuffer->Release();
	m_renderData.VertexBuffer = nullptr;
	if( m_renderData.IndexBuffer ) m_renderData.IndexBuffer->Release();
	m_renderData.IndexBuffer = nullptr;
	m_triangleAccessors.clear();
}

void Model::UpdateVertexBuffer( ID3D11DeviceContext* d3dContext)
{
	d3dContext->UpdateSubresource(m_renderData.VertexBuffer,
		0,
		nullptr,
		m_rawData.vertices,
		0,
		0);
}

//attention: does return an empty vector if model hasn't yet been added to graphicsrenderer
std::vector<TriangleAccessor>* Model::GetTriangleAccessors( void )
{
	assert(!m_triangleAccessors.empty());
	return &m_triangleAccessors;
}